home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
embedded
/
develop
/
libsrc11.arc
/
AUTOSUPP.S
< prev
next >
Wrap
Text File
|
1989-04-27
|
6KB
|
206 lines
* /* autosupp.s 4.2 */
*
xdef dmulu
*
* dmulu - 32 by 32 multiply giving low 32 bits of result
* This is an UNSIGNED multiply.
*
* DMULU multiplies Operand 1 by Operand 2 storing the result
* in Operand 3. The algorithm used initially sets the
* high two words of result (words 0 and 1) to zero and
* the low two words of result to Operand 1. The multiply
* is done by seeing if the low bit of result word 3 is
* set, if it is then Operand 2 is added to result words
* 0 and 1. Then, whether the add was done or not, all
* of result is shifted right one with the most significant
* being the carry of the last add or zero if no add was
* done. This process of checking low bit of result word 3,
* conditionally adding Operand 2, and then shifting Result
* right is repeated 32 times (shift count).
*
* A clever algorithm, for it does multiplication by dividing
* by 2 (shifting right)...
*
* Equates:
lo equ 2 low word of operand
hi equ 0 high word of operand
*
shift equ 0 shift count
res equ 1 result
reslo32 equ 5 result - low 32 bits
savex equ 9 saved x
rtnPC equ 11 return pc
op3 equ 13 result returned pointer
*
* Parameters:
* Operand 1 -> D register.
* This is a pointer to the multiplicand (32 bits).
* Operand 2 -> Y register.
* This is a pointer to the multiplier (32 bits).
* Operand 3 -> 1st word on stack after return PC
* This is a pointer to the low 32 bits of the product.
*
dmulu pshx save x register
xgdy swap parameters temporarily
ldx lo,%y store operand 1 in result lo 32
pshx
ldx hi,%y
pshx
ldx #0
pshx result word 1
pshx result word 0
xgdy reset parameters
ldaa #32 shift count (clobbers operand 1--no longer needed)
psha put shift count onto stack
tsx set x to point to parameter/work area
*
* stack register/stack/x register look like:
*
* x,s -> shift count 0,%x tos
* -> result word 0 1,%x tos+1
* -> result word 1 3,%x tos+3
* -> result word 2 5,%x tos+5
* -> result word 3 7,%x tos+7
* -> saved x 9,%x tos+9
* -> return PC 11,%x tos+11
* -> op 3 ptr (result) 13,%x tos+13
*
* y = op 2 ptr
*
* Note: "tos" stands for top of stack
* The stack looks the same for DDIVU once all the
* work space has been allocated.
*
mul_loop:
clc reset carry bit...
brclr reslo32+lo+1,%x,#1,skip
ldd lo,%y add to result low of op 2
addd res+lo,%x result word 1
std res+lo,%x new result word 1
ldd hi,%y add to result hi of op 2
adcb res+hi+1,%x
adca res+hi,%x add to result word 0
std res+hi,%x save in result word 0
skip:
ror res+hi,%x
ror res+hi+1,%x
ror res+lo,%x
ror res+lo+1,%x
ror reslo32+hi,%x
ror reslo32+hi+1,%x
ror reslo32+lo,%x
ror reslo32+lo+1,%x
dec shift,%x decrement shift count
bne mul_loop
*
* done... clean up the mess...
*
ldy op3,%x get pointer to result
ldab #reslo32 remove shift count, high 32 bits of result
abx (up to low 32 bits of result)
txs
pulx get result word 2
stx hi,%y store in operand 3
pulx get result word 3
stx lo,%y store in operand 3
pulx restore x
rts done... finally (whew!)
*
xdef ddivu
*
* ddivu - 32 by 32 divide giving a 32 bit remainder and
* a 32 bit quotient. This is an UNSIGNED divide.
*
* DDIVU divides Operand 1 by Operand 2 storing the remainder
* and the quotient in Operand 3. The algorithm takes Operand
* 1 and stores in quotient. The Y register points to Operand 2.
* The remainder is initially zero.
*
* The actual divide is done by shifting the result (remainder and
* quotient) left 1 bit at a time. Operand 2 is then subtracted
* from remainder (Operand 1 shifted in one bit at a time). If
* Operand 2 is less than or equal the current remainder (no carry),
* then the subtraction is completed and low bit of the quotient
* is set on the next left shift. If Operand 2 is greater than the
* current remainder, then the subtraction is undone (through addition)
* and the low bit of the quotient is cleared on the next left shift.
*
* Equates:
rem equ 1 remainder
quo equ 5 quotient
*
* note: the equates:
* shift, savex, rtnPC, op3 are same as DMULU
*
op3_quo equ 4 offset to operand 3 quotient (result)
*
* Parameters:
* Op1 -> ptr to dividend (D register)
* Op2 -> ptr to divisor (Y register)
* Op3 -> ptr to result (1st word on stack after return PC)
*
* Comments: Operand 1 and Operand 2 are each 32 bits long.
* Operand 3 (result is 64 bits long). The hi 32 bits of
* result is the remainder. The low 32 bits of the result
* is the quotient.
*
ddivu pshx save x
xgdy swap parameters temporarily
ldx lo,%y get operand 1 (dividend)
pshx initialize quotient
ldx hi,%y
pshx
ldx #0 set remainder to zero initially
pshx
pshx
xgdy reset parameters
ldaa #33 shift count (32 bits plus extra bit in quotient)
psha
tsx point to work area/operands on stack
* value for 1st shift is not used, not important (low bit for quotient)
* (because we shift quotient 33 times, 33rd bit goes to bit bucket)
div_loop
rol quo+lo+1,%x save result of previous division
rol quo+lo,%x
rol quo+hi+1,%x
rol quo+hi,%x
dec shift,%x done?
beq div_done
rol rem+lo+1,%x update remainder, more to do
rol rem+lo,%x
rol rem+hi+1,%x
rol rem+hi,%x
ldd rem+lo,%x
subd lo,%y subtract divisor
std rem+lo,%x
ldd rem+hi,%x
sbcb hi+1,%y borrow needed bits...
sbca hi,%y
bcc skip_add rem >= divisor, can divide
* undo subtract
ldd rem+lo,%x
addd lo,%y
std rem+lo,%x
clc shift in zero into quotient, cannot divide
bra div_loop
* finish subtract...
skip_add:
std rem+hi,%x
sec shift in one into quotient, can divide
bra div_loop
*
div_done:
ldy op3,%x save results
pula
pulx
stx hi,%y save hi of remainder
pulx
stx lo,%y save low of remainder
pulx
stx op3_quo+hi,%y save hi of quotient
pulx
stx op3_quo+lo,%y save lo of quotient
pulx restore x
rts exit stage right (or left...)
end